package StorageEngine

import (
	"KumquatDrivesServices/global"
	"KumquatDrivesServices/model"
	"errors"
	"fmt"
	"github.com/go-redis/redis"
	"github.com/sirupsen/logrus"
	"mime/multipart"
	"os"
	"time"
)

type StorageEngineStruct interface {
	InitiateMultipartUpload(userId model.SnowflakeIdType) EngineID
	DelTempFile(uploadId EngineID) error
	MergeTempFiles(uploadId EngineID, userId model.SnowflakeIdType, destFilename string, fileSize int64) (string, int64, error)
	SaveTempFile(uploadId EngineID, userId model.SnowflakeIdType, tmpFileIndex int, tmpFile *multipart.FileHeader) error
	CreateVideoThumbnail(srcPath string) (string, error)
	CutFileForVideo(srcPath string) error
	RemoveMergeFile(srcPath string) error
	GenerateThumbnail(srcPath string) (string, error)
	GetCoverImage(UserEmail string, fileName string) ([]byte, error)
	GetFile(filePath string, fileName string) ([]byte, error)
	GetFileContentType(buffer []byte) string
	GetFileWithMetadata(filePath, fileName string) (*os.File, error)
}

var (
	InvalidEngineIDErr = errors.New("invalid engine id")
	ErrFileNotExistErr = errors.New("file not exist")
	Engine             StorageEngineStruct
)

type EngineID string

func (str EngineID) String() string {
	return string(str)
}
func (str EngineID) getKey(userID model.SnowflakeIdType) string {
	return fmt.Sprintf("file:%s_%d", str, userID)
}
func (str EngineID) SetTempFileSize(userID model.SnowflakeIdType, fileSize int64) error {
	Key := str.getKey(userID)
	bol, err := str.IsDiscard(userID)
	if err != nil {
		logrus.Errorf("err:%v", err)
		return err
	}
	if bol {
		return InvalidEngineIDErr
	}
	if err = global.Redis.IncrBy(Key, fileSize).Err(); err != nil {
		if errors.Is(err, redis.Nil) {
			if err = global.Redis.Set(Key, fileSize, time.Hour).Err(); err != nil {
				return err
			}
		} else {
			return err
		}
	}
	if _, err = global.Redis.Expire(Key, time.Hour).Result(); err != nil {
		return err
	}
	return nil
}
func (str EngineID) GetTempFileSize(userID model.SnowflakeIdType) (int64, error) {
	Key := str.getKey(userID)
	bol, err := str.IsDiscard(userID)
	if err != nil {
		logrus.Errorf("err:%v", err)
		return 0, err
	}
	if bol {
		return 0, InvalidEngineIDErr
	}
	redisFileSize, RedisErr := global.Redis.Get(Key).Int64()
	if RedisErr != nil {
		if errors.Is(RedisErr, redis.Nil) {
			return 0, nil
		}
		return 0, RedisErr
	}
	return redisFileSize, nil
}
func (str EngineID) DeleteTempFileSize(userID model.SnowflakeIdType) error {
	Key := str.getKey(userID)
	if err := global.Redis.Del(Key).Err(); err != nil {
		if errors.Is(err, redis.Nil) {
			return nil
		}
		return err
	}
	if err := str.SetDiscard(userID); err != nil {
		return err
	}
	return nil
}
func (str EngineID) IsDiscard(userID model.SnowflakeIdType) (bool, error) {
	key := fmt.Sprintf("file:Discard_%s_%d", str, userID)
	if _, err := global.Redis.Get(key).Result(); err != nil {
		if errors.Is(err, redis.Nil) {
			return false, nil
		}
		return true, err
	}
	return true, nil
}
func (str EngineID) SetDiscard(userID model.SnowflakeIdType) error {
	key := fmt.Sprintf("file:Discard_%s_%d", str, userID)
	if err := global.Redis.Set(key, "1", time.Hour).Err(); err != nil {
		return err
	}
	return nil
}
